package br.ufpi.hu.prescricao.managedbeans;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;


//import br.ufpi.hu.prescricao.facade.AghuFacade;
import br.ufpi.hu.prescricao.facade.LaudoFacade;
import br.ufpi.hu.prescricao.model.LaudoBase;
import br.ufpi.hu.prescricao.model.Usuario;

public class LaudoLazyDataModel extends LazyDataModel<LaudoBase> {

	private static final long serialVersionUID = 8154176309208400088L;

	private LaudoFacade laudoFacade;
//	private AghuFacade aghuFacade;
	
	public LaudoFacade getLaudoFacade() {
		return laudoFacade;
	}

	public void setLaudoFacade(LaudoFacade laudoFacade) {
		this.laudoFacade = laudoFacade;
	}

//	public AghuFacade getAghuFacade() {
//		return aghuFacade;
//	}
//
//	public void setAghuFacade(AghuFacade aghuFacade) {
//		this.aghuFacade = aghuFacade;
//	}

	private String texto;
	
	private Date dataFinal;
	private Date dataInicial;
	private Usuario usuarioDaSessao;

	public String getTexto() {
		return texto;
	}
	
	public Date getDataFinal() {
		return dataFinal;
	}

	public void setDataFinal(Date dataFinal) {
		this.dataFinal = dataFinal;
	}

	public Date getDataInicial() {
		return dataInicial;
	}

	public void setDataInicial(Date dataInicial) {
		this.dataInicial = dataInicial;
	}

	public void setTexto(String texto) {
		this.texto = texto;
	}

	public Usuario getUsuarioDaSessao() {
		return usuarioDaSessao;
	}

	public void setUsuarioDaSessao(Usuario usuarioDaSessao) {
		this.usuarioDaSessao = usuarioDaSessao;
	}

	public LaudoLazyDataModel() {}

	@Override  
	public Object getRowKey(LaudoBase modelo) {  
		return Integer.toString(modelo.getId());  
	}

	/* Necessario, java.lang.ArithmeticException em LazyDataModel
	 * 
	 * (non-Javadoc)
	 * @see org.primefaces.model.LazyDataModel#setRowIndex(int)
	 */
	@Override
	public void setRowIndex(int rowIndex) {
		if (rowIndex == -1 || getPageSize() == 0) {
			super.setRowIndex(-1);
		}
		else
			super.setRowIndex(rowIndex % getPageSize());
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public List<LaudoBase> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,String> filters) {

		setPageSize(pageSize);

		List<LaudoBase> data = new ArrayList<LaudoBase>();

		EntityManager em = laudoFacade.getLaudoDAO().getEntityManager();

		CriteriaQuery<LaudoBase> cq = em.getCriteriaBuilder().createQuery(LaudoBase.class);
		Root root = cq.from(LaudoBase.class);

		if (sortField == null)
		{
			sortField = "dataDeCriacao";
			sortOrder = SortOrder.DESCENDING;
		}

		//sort
		if(sortField != null && !sortField.equals("tipo")) {


			Path expression = null;

			if (sortField.equals("usuarioDaSessao.nome")) { //caso altere as colunas, mudar isso
				expression = root.get("usuarioDaSessao").get("nome");
			}
			else
			{
				expression = root.get(sortField);
			}


			if (sortOrder == SortOrder.ASCENDING) {
				cq.orderBy(em.getCriteriaBuilder().asc(expression));
			}
			else {
				cq.orderBy(em.getCriteriaBuilder().desc(expression));
			}

		}

		// filters
		List<Predicate> predicates = new ArrayList<Predicate>();

		if (usuarioDaSessao!=null){

			predicates.add(em.getCriteriaBuilder().equal(root.get("usuarioDaSessao"), usuarioDaSessao));

		}

		if (texto!=null) {
			predicates.add(em.getCriteriaBuilder().like(root.<String>get("texto"), "%"+texto+"%"));
		}

		if (dataInicial!=null) {

			Calendar cal = Calendar.getInstance();
			cal.clear();
			cal.setTime( dataInicial );
			cal.set(Calendar.HOUR_OF_DAY, 0);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);
			cal.set(Calendar.MILLISECOND, 0);
			dataInicial = cal.getTime();

			predicates.add(em.getCriteriaBuilder().greaterThanOrEqualTo(root.get("data"), dataInicial));

		}

		if (dataFinal!=null) {

			Calendar cal = Calendar.getInstance();
			cal.clear();
			cal.setTime( dataFinal );
			cal.set(Calendar.HOUR_OF_DAY, 23);
			cal.set(Calendar.MINUTE, 59);
			cal.set(Calendar.SECOND, 59);
			cal.set(Calendar.MILLISECOND, 999);
			dataFinal = cal.getTime();

			predicates.add(em.getCriteriaBuilder().lessThanOrEqualTo(root.get("data"), dataFinal));

		}

		for(Iterator<String> it = filters.keySet().iterator(); it.hasNext();) {

			String filterProperty = it.next(); // table column name = field name
			String filterValue = filters.get(filterProperty);

			Expression<String> literal = em.getCriteriaBuilder().literal((String) filterValue);
			predicates.add(em.getCriteriaBuilder().equal(root.get(filterProperty), literal));
		}
		cq.where(predicates.toArray(new Predicate[predicates.size()]));

		// paginate
		data = em.createQuery(cq).setFirstResult(first)
				.setMaxResults(getPageSize()).getResultList();

		// row count
		CriteriaQuery<Long> countQuery = em.getCriteriaBuilder().createQuery(Long.class);
		countQuery.select(em.getCriteriaBuilder().count(countQuery.from(LaudoBase.class)));
		countQuery.where(predicates.toArray(new Predicate[predicates.size()]));
		int rowCount = em.createQuery(countQuery).getSingleResult().intValue();
		setRowCount(rowCount);

		//aghu paciente
//		for (LaudoBase laudo : data) {
//			laudo.setPaciente(aghuFacade.loadPacienteById(laudo.getIdPacienteAghu()));
//		}

		if (sortField.equals("tipo")) {

			Collections.sort(data, new LazySorterLaudo(sortField, sortOrder));

		}

		return data;

	}

	@Override
	public LaudoBase getRowData(String rowKey) {

		int id = Integer.parseInt(rowKey);

		return (LaudoBase)laudoFacade.find(id);

	}
}

